import type { IEventTarget } from "./interfaces";
import type { Event } from "./Event";

/**
 * Represents event listener options (partial implementation)
 */
interface EventListenerOptions {
    capture?: boolean;
    once?: boolean;
    passive?: boolean;
    //signal?: AbortSignal;
}

/**
 * Event handler function type
 */
type EventHandler = (event: Event) => Promise<void> | void;


/**
 * Objects that can receive events and may have listeners for them.
 * eg. Element, Canvas, DisplayObject
 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
 */
export class EventTarget implements IEventTarget {
    private _disposed = false;
    get disposed(): boolean { return this._disposed; }

    protected readonly _eventHandlers: Record<string, EventHandler[]> = {};
    protected readonly _eventCaptureHandlers: Record<string, EventHandler[]> = {};

    addEventListener(eventType: string, eventHandler: EventHandler, options?: EventListenerOptions): void {
        if (this._disposed) return;

        const capture = options?.capture ?? false;
        let existHandler = capture
            ? this._eventCaptureHandlers[eventType]
            : this._eventHandlers[eventType];

        if (!existHandler) {
            if (capture)
                this._eventCaptureHandlers[eventType] = existHandler = [];
            else
                this._eventHandlers[eventType] = existHandler = [];
        }
        existHandler.push(eventHandler);
    }

    removeEventListener(eventType: string, eventHandler: EventHandler, isCapture = false): void {
        if (this._disposed) return;

        const currentHandlers = isCapture
            ? this._eventCaptureHandlers[eventType]
            : this._eventHandlers[eventType];


        if (currentHandlers.length >= 0) {
            const index = currentHandlers?.indexOf(eventHandler) ?? -1;
            if (index >= 0) {
                currentHandlers.splice(index, 1);
            }
            if (currentHandlers.length === 0) {
                if (isCapture) {
                    delete this._eventCaptureHandlers[eventType];
                } else {
                    delete this._eventHandlers[eventType];
                }
            }
        }
    }

    async dispatchEvent(event: Event): Promise<void> {
        if (this._disposed) return;

        // Simplified target assignment
        event.target = this;

        // Capture phase
        await this._handleCapturePhase(event);

        // Bubble phase
        await this._handleBubblePhase(event);
    }


    getEventHandlers(): Record<string, EventHandler[]> {
        return this._eventHandlers;
    }

    getCaptureEventHandlers(): Record<string, EventHandler[]> {
        return this._eventCaptureHandlers;
    }

    protected hasEventListener(type: string): boolean {
        return !!this._eventHandlers[type]?.length;
    }

    private async _handleCapturePhase(event: Event): Promise<void> {
        // Walk up the parent chain first (capture phase)
        if (this.parentEventTarget) {
            await (this.parentEventTarget as EventTarget)._handleCapturePhase(event);
        }

        const existHandler = this._eventCaptureHandlers[event.type];
        if (existHandler?.length) {
            event.currentTarget = this;
            // Create a copy to prevent concurrent modification
            const handlers = [...existHandler];

            // Execute in reverse registration order
            for (let i = handlers.length - 1; i >= 0; i--) {
                try {
                    handlers[i](event);
                } catch (error) {
                    console.error('Error in capture handler:', error);
                }
            }
            event.currentTarget = null;
        }
    }

    private async _handleBubblePhase(event: Event): Promise<void> {
        // Target phase handlers
        const handlers = this._eventHandlers[event.type];
        if (handlers?.length) {
            event.currentTarget = this;
            const handlersCopy = [...handlers];

            for (let i = handlersCopy.length - 1; i >= 0; i--) {
                try {
                    await handlersCopy[i](event);
                } catch (error) {
                    console.error('Error in bubble handler:', error);
                }
            }
            event.currentTarget = null;
        }

        // Continue bubbling
        if (event.bubbles && !event.propagationStopped) {
            if (this.parentEventTarget) {
                await (this.parentEventTarget as EventTarget).dispatchEvent(event);
            }
        }
    }

    dispose(): void {
        this._disposed = true;
        this._clearHandlers(this._eventHandlers);
        this._clearHandlers(this._eventCaptureHandlers);
        // super.dispose();
    }

    private _clearHandlers(handlers: Record<string, EventHandler[]>): void {
        for (const key of Object.keys(handlers)) {
            delete handlers[key];
        }
    }

    abstract get parentEventTarget(): EventTarget | null;

    get eventPath(): EventTarget[] {
        const path: EventTarget[] = [];
        let current: EventTarget | null = this;

        while (current) {
            path.push(current);
            current = current.parentEventTarget;
        }
        return path;
    }
}
